// Copyright (c) [Year] [name of copyright holder]
// [Software Name] is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2. 
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2 
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
// See the Mulan PSL v2 for more details.


/*!
 * \autor captainpeng
 * \date 2019-1-15
 * \update 2019-1-15
 * \version 1.0
 * \copyright
 */

#ifndef MY_TYPEOP_HPP
#define MY_TYPEOP_HPP

#include<type_traits>
#include"typeDecl.hpp"
#include"typeTuple.hpp"

// 因为类型循环还是没有琢磨透，所以我加了三个参数来当作一个循环使用
// 例如1
// bool STARTFLAG = ...;
// if(STARTFLAG){
//     for(INDEX = ...; ENDFLAG; INDEX++){
//         部位1;
//     }
//     部位2;
//  }
// 部位3;

// 我的大概就是模仿上述循环建立的
// template< ... /* 一些输入的参数 */, int INDEX, bool ENDFLAG, bool STARTFLAG>
// struct typeLoop;
//
// template< ..., int INDEX>
// struct typeLoop<..., INDEX, true, true> 该特例类是要进行运算的内容，部位1
//
// template< ..., int INDEX>
// struct typeLoop<..., INDEX, false, true> 该特例类是循环结束的内容，部位2
//
// template< ..., int INDEX, bool ENDFLAG>
// struct typeLoop<..., INDEX, ENDFLAG, false> 该特例类是不符合条件的内容，部位3

// 例如2
// bool STARTFLAG = ...;
// if(STARTFLAG){
//     for(INDEX1 = ...; ENDFLAG1; INDEX1++){
//         for(INDEX2 = ...; ENDFLAG2; INDEX1++){
//             部位1;
//         }
//         部位2;
//     }
//     部位3;
// }
// 部位4;

// template<... /* 一些输入的参数 */, int INDEX, bool ENDFLAG>
// struct typeInnLoop;

// template<... /* 一些输入的参数 */, int INDEX>
// struct typeInnLoop<..., INDEX, true>; 部位1

// template<... /* 一些输入的参数 */, int INDEX>
// struct typeInnLoop<..., INDEX, false>; 部位1结束条件

// template<... /* 一些输入的参数 */, int INDEX, bool ENDFLAG, bool STARTFLAG>
// struct typeOutLoop;

// template<... /* 一些输入的参数 */, int INDEX>
// struct typeOutLoop<..., INDEX, true, true>; 部位2

// template<... /* 一些输入的参数 */, int INDEX>
// struct typeOutLoop<..., INDEX, false, true>; 部位3

// template<... /* 一些输入的参数 */, int INDEX, bool ENDFLAG>
// struct typeOutLoop<..., INDEX, false>; 部位4

namespace my{
    // typeOpEqual 输入类型集合 LHS 和 RHS, 检查每个元素是否相同，有顺序要求。
    template<typename LHS, typename RHS, int INDEX, bool ENDFLAG, bool STARTFLAG>
    struct typeOpEqual;

    template<typename LHS, typename RHS, int INDEX>
    struct typeOpEqual<LHS, RHS, INDEX, true, true>{
        using t1 = typename typeTupleGet<LHS, INDEX>::type;
        using t2 = typename typeTupleGet<RHS, INDEX>::type;
        static const bool value =
            std::is_same<t1, t2>::value &&
            typeOpEqual<LHS, RHS, INDEX+1, (INDEX+1 < LHS::size && INDEX+1 < RHS::size), true>::value;
    };

    template<typename LHS, typename RHS, int INDEX>
    struct typeOpEqual<LHS, RHS, INDEX, false, true>{
        static const bool value = true;
    };

    template<typename LHS, typename RHS, int INDEX, bool ENDFLAG>
    struct typeOpEqual<LHS, RHS, INDEX, ENDFLAG, false>{
        static const bool value = false;
    };

    // typeOpInclude 输入类型集合 LHS 和 RHS, 检查 RHS 中每个类型是否都在 LHS 里, 无顺序要求。
    template<typename LHS, typename TYPE, int INDEX, bool ENDFLAG>
    struct typeOpIncludeInn;

    template<typename LHS, typename TYPE, int INDEX>
    struct typeOpIncludeInn<LHS, TYPE, INDEX, true>{
        using t1 = typename typeTupleGet<LHS, INDEX>::type;

        static const bool value = std::is_same<t1, TYPE>::value || typeOpIncludeInn<LHS, TYPE, INDEX+1, (INDEX+1 < LHS::size)>::value;
    };

    template<typename LHS, typename TYPE, int INDEX>
    struct typeOpIncludeInn<LHS, TYPE, INDEX, false>{
        static const bool value = false;
    };

    template<typename LHS, typename RHS, int INDEX, bool ENDFLAG, bool STARTFLAG>
    struct typeOpInclude;

    template<typename LHS, typename RHS, int INDEX>
    struct typeOpInclude<LHS, RHS, INDEX, true, true>{
        using t2 = typename typeTupleGet<RHS, INDEX>::type;
        static const bool value = typeOpIncludeInn<LHS, t2, 0, true>::value && typeOpInclude<LHS, RHS, INDEX+1, (INDEX+1 < RHS::size), true>::value;
    };

    template<typename LHS, typename RHS, int INDEX>
    struct typeOpInclude<LHS, RHS, INDEX, false, true>{
        static const bool value = true;
    };

    template<typename LHS, typename RHS, int INDEX, bool ENDFLAG>
    struct typeOpInclude<LHS, RHS, INDEX, ENDFLAG, false>{
        static const bool value = false;
    };

    // typeOpFuncEqual 输入类型集合 LHS 和 RHS, 检查每个元素是否相同，有顺序要求。
    // 与上述 typeOpEqual 不同的是，用于函数的判断忽略了引用和正常类型的区别，即默认
    // int & == int, int && == int  依次类推
    template<typename LHS, typename RHS, int INDEX, bool ENDFLAG, bool STARTFLAG>
    struct typeOpFuncEqual;

    template<typename LHS, typename RHS, int INDEX>
    struct typeOpFuncEqual<LHS, RHS, INDEX, true, true>{
        using t1 = typename std::remove_reference<typename typeTupleGet<LHS, INDEX>::type>::type;
        using t2 = typename std::remove_reference<typename typeTupleGet<RHS, INDEX>::type>::type;
        static const bool value =
            std::is_same<t1, t2>::value &&
            typeOpFuncEqual<LHS, RHS, INDEX+1, (INDEX+1 < LHS::size && INDEX+1 < RHS::size), true>::value;
    };

    template<typename LHS, typename RHS, int INDEX>
    struct typeOpFuncEqual<LHS, RHS, INDEX, false, true>{
        static const bool value = true;
    };

    template<typename LHS, typename RHS, int INDEX, bool ENDFLAG>
    struct typeOpFuncEqual<LHS, RHS, INDEX, ENDFLAG, false>{
        static const bool value = false;
    };

    // typeOpFuncInclude 输入类型集合 LHS 和 RHS, 检查 RHS 中每个类型是否都在 LHS 里, 无顺序要求。
    // 同理，默认引用和正常类型一致 int & == int, int && == int 依次类推
    template<typename LHS, typename TYPE, int INDEX, bool ENDFLAG>
    struct typeOpFuncIncludeInn;

    template<typename LHS, typename TYPE, int INDEX>
    struct typeOpFuncIncludeInn<LHS, TYPE, INDEX, true>{
        using t1 = typename std::remove_reference<typename typeTupleGet<LHS, INDEX>::type>::type;

        static const bool value = std::is_same<t1, TYPE>::value || typeOpFuncIncludeInn<LHS, TYPE, INDEX+1, (INDEX+1 < LHS::size)>::value;
    };

    template<typename LHS, typename TYPE, int INDEX>
    struct typeOpFuncIncludeInn<LHS, TYPE, INDEX, false>{
        static const bool value = false;
    };

    template<typename LHS, typename RHS, int INDEX, bool ENDFLAG, bool STARTFLAG>
    struct typeOpFuncInclude;

    template<typename LHS, typename RHS, int INDEX>
    struct typeOpFuncInclude<LHS, RHS, INDEX, true, true>{
        using t2 = typename std::remove_reference<typename typeTupleGet<RHS, INDEX>::type>::type;
        static const bool value = typeOpFuncIncludeInn<LHS, t2, 0, true>::value && typeOpFuncInclude<LHS, RHS, INDEX+1, (INDEX+1 < RHS::size), true>::value;
    };

    template<typename LHS, typename RHS, int INDEX>
    struct typeOpFuncInclude<LHS, RHS, INDEX, false, true>{
        static const bool value = true;
    };

    template<typename LHS, typename RHS, int INDEX, bool ENDFLAG>
    struct typeOpFuncInclude<LHS, RHS, INDEX, ENDFLAG, false>{
        static const bool value = false;
    };
    
    // 用法 typeOp<要求的>::运算符<输入的>::value
    template<typename ... LHSTYPES>
    struct typeOp{
        using lhsTuple = typeTuple<LHSTYPES ...>;

        template<typename ... RHSTYPES>
        struct equal{
            using rhsTuple = typeTuple<RHSTYPES ...>;
            static const bool value = typeOpEqual<lhsTuple, rhsTuple, 0, true, lhsTuple::size == rhsTuple::size && lhsTuple::size != 0>::value;
        };

        template<typename ... RHSTYPES>
        struct include{
            using rhsTuple = typeTuple<RHSTYPES ...>;
            static const bool value = typeOpInclude<lhsTuple, rhsTuple, 0, true, true>::value;
        };

        // 函数系列会去掉引用
        template<typename ... RHSTYPES>
        struct func_equal{
            using rhsTuple = typeTuple<RHSTYPES ...>;
            static const bool value = typeOpFuncEqual<lhsTuple, rhsTuple, 0, true, lhsTuple::size == rhsTuple::size && lhsTuple::size != 0>::value;

        };

        template<typename ... RHSTYPES>
        struct func_include{
            using rhsTuple = typeTuple<RHSTYPES ...>;
            static const bool value = typeOpFuncInclude<lhsTuple, rhsTuple, 0, true, true>::value;
        };

    };
}

#endif
